﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace nwrole.console
{
    public class Command
    {
        public List<string> Names { get;set; }
        public Type ContainerType { get; set; }
        public MethodInfo Method { get; set; }
        public Dictionary<string, object> DefaultValues { get; set; }
        public bool IsGeneric { get; set; }

        public bool Run (Dictionary<string, object> parameters)
        {
            CommandBase obj = (CommandBase)Activator.CreateInstance(ContainerType);

            if (IsGeneric)
            {
                Method.Invoke(obj, new object[] { parameters });
            }
            else
            {
                ParameterInfo[] parameterInfos = Method.GetParameters();

                // Check input parameter names
                foreach (string name in parameters.Keys)
                {
                    if ((from info in parameterInfos where info.Name.Equals(name, StringComparison.OrdinalIgnoreCase) select info).FirstOrDefault() == null)
                        return false;
                }

                Dictionary<string, object> inputs = new Dictionary<string, object>(DefaultValues, StringComparer.OrdinalIgnoreCase);
                foreach (var kvp in parameters)
                    inputs[kvp.Key] = kvp.Value;

                // Verify that all variables exists
                foreach (ParameterInfo info in parameterInfos)
                {
                    if (!inputs.ContainsKey(info.Name))
                        return false;
                }

                object[] parameterInputs = new object[parameterInfos.Length];
                for (int i = 0; i < parameterInputs.Length; i++)
                    parameterInputs[i] = Convert.ChangeType(inputs[parameterInfos[i].Name], parameterInfos[i].ParameterType);

                Method.Invoke(obj, parameterInputs);
            }

            return true;
        }

        public bool IsOptional (string parameterName)
        {
            foreach (ParameterInfo info in Method.GetParameters())
            {
                if (parameterName.Equals(info.Name, StringComparison.OrdinalIgnoreCase))
                {
                    if (info.GetCustomAttributes(typeof(OptionalAttribute), true).FirstOrDefault() != null)
                        return true;
                    return false;
                }
            }
            return false;
        }
    }
}
